package com.wjm.http;

import java.io.*;
import java.net.Socket;

/**
 * Data:2022年08月13日
 * Author:wjm
 * Content:
 *
 *     HttpResponse的每一个实例对象都是用来表示给客户端发送一个Http的响应
 *
 *     响应有三部分组成：
 *          状态行、响应头、响应正文
 *
 */
public class HttpResponse {
    //声明一个socket变量
    private Socket socket;

    /*
    * 状态行
    * */
    private int statusCode = 200; //状态码，默认200，表示资源存在
    private String statusReason = "OK"; //状态描述，

    /*
    * TODO 响应头
    * */

    /*
    *  响应正文
    * */
    private File fileEntity;


    //get()和set()还有 构造方法
    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public String getStatusReason() {
        return statusReason;
    }

    public void setStatusReason(String statusReason) {
        this.statusReason = statusReason;
    }

    public File getFileEntity() {
        return fileEntity;
    }

    public void setFileEntity(File fileEntity) {
        this.fileEntity = fileEntity;
    }

    public HttpResponse(Socket socket){
        this.socket = socket;
    }


    /**
     * 统一管理和发送状态行、响应头、响应正文的方法
     */
    public void flush(){
       sendStatusLine();
       sendHeaders();
       sendContent();
    }

    /**
     * 发送状态行的方法
     */
    public void sendStatusLine(){
        //状态行
        String line = "Http/1.1 "+statusCode+""+statusReason;
        //将状态行写出到输出流
        writeLine(line);
        System.out.println("状态行发送完毕！");

    }

    /**
     * 发送响应头的方法
     */
    public void sendHeaders(){
        //需要发送的消息头
        String line = "Content-Type: text/html";
        //将消息头写出到输出流
        writeLine(line);

        //需要发送的消息头
        line = "Content-Length: "+fileEntity.length();
        //将消息头写出到输出流
        writeLine(line);

        //响应头全部发送结束，是以单独的连续的两个字符作为标识
        //out.write(13); //CR
        //out.write(10); //LF
        writeLine("");//表示另起一行空白行，效果与CRLF一样
        System.out.println("响应头发送完毕！");


    }

    /**
     * 发送响应正文的方法
     */
    public void sendContent() {
        try{
            //创建字节输入流对象读取，所需文件内容
            FileInputStream fileInputStream = new FileInputStream(fileEntity);
            //获取字节输出流
            OutputStream out =socket.getOutputStream();
            //创建一个读取文件的字节数组
            byte[] bytes1 = new byte[5*1024];
            int len;
            while ((len = fileInputStream.read(bytes1)) != -1){
                //将读取到的内容写出
                /*
                 * 因为只有字节数组bytes1装满的才会写出，所以为了解决这个问题，我们需要用重载的write方法
                 * 当用字节数组来读取文件时，len其实表示的就是字节数组bytes1的长度
                 * */
                out.write(bytes1,0,len);
            }
            System.out.println("响应正文发送完毕！");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 这是一个写一行的方法，将需要发送的字符串传进来，并写出到输出流中
     * 封装了发送状态行方法(sendStatusLine)和发送响应头方法(sendHeaders)中的相同代码
     *
     * @param line 需要写出的字符串
     */
    public void writeLine(String line){
        try{
            //获取字节输出流
            OutputStream out =socket.getOutputStream();
            //将字符串转为字节数组
            byte[] bytes = line.getBytes("ISO8859-1");
            out.write(bytes);
            //状态行的结束是以两个连续的字符作为标识[CRLF]，响应头一行的结束也是以两个连续的字符作为标识[CRLF]
            out.write(13); //CR
            out.write(10); //LF
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
